/**
 * @file message_utils.cpp
 * @author 王烨
 * @date 2011-01-09
**/
#include <cstdlib>

#include "message.pb.h"

#include "error.h"
#include "message_utils.h"

namespace skeleton
{
  using namespace std;
  using namespace google::protobuf;

  /*客户端序列化发送的RPC请求*/
  static void GenerateRequest(const MethodDescriptor &descriptor,
			      const Message &parameters,
			      Request &request)
  {
    //每个请求通过一个uuid来标识
    uuid_t uuid;
    uuid_generate(uuid);
    request.set_uuid(&uuid, sizeof(uuid));
    
    //设定请求的RPC方法
    string serviceName = descriptor.service()->name();
    request.set_servicename(serviceName);
    request.set_methodname(descriptor.name());
    string parametersData = parameters.SerializeAsString();
    request.set_parameters(parametersData);
  }

  string SerializeRequest(const MethodDescriptor &descriptor,
			  const Message &parameters)
  {
    Request request;
    GenerateRequest(descriptor, parameters, request);
    return request.SerializeAsString();
  }

  void SerializeRequest(const MethodDescriptor &descriptor,
			const Message &parameters,
			string &requestData)
  {
    Request request;
    GenerateRequest(descriptor, parameters, request);
    request.SerializeToString(&requestData);
  }

  void SerializeRequest(const MethodDescriptor &descriptor,
			const Message &parameters,
			void *requestData,
			int length)
  {
    Request request;
    GenerateRequest(descriptor, parameters, request);
    request.SerializeToArray(requestData, length);
  }

  /*服务端序列化发送的RPC响应*/
  static void GenerateResponse(const uuid_t &uuid,
			       const Message &message,
			       bool isErrorMessage,
			       Response &response)
  {
    response.set_uuid(uuid, sizeof(uuid_t));
    if (isErrorMessage)
      {
	Error *error = response.mutable_error();
	*error = dynamic_cast<const Error&>(message);
      }
    else
      {
	 string *result = response.mutable_result();
	 *result = message.SerializeAsString();
      }
  }
				
  string SerializeResponse(const uuid_t &uuid,
			   const Message &message,
			   bool isErrorMessage)
  {
    Response response;
    GenerateResponse(uuid, message, isErrorMessage, response);
    return response.SerializeAsString();
  }

  void SerializeResponse(const uuid_t &uuid,
			 const Message &message,
			 string &responseData,
			 bool isErrorMessage)
  {
    Response response;
    GenerateResponse(uuid, message, isErrorMessage, response);
    response.SerializeToString(&responseData);
  }

  void SerializeResponse(const uuid_t &uuid,
			 const Message &message,
			 void *responseData,
			 int length,
			 bool isErrorMessage)
  {
    Response response;
    GenerateResponse(uuid, message, isErrorMessage, response);
    response.SerializeToArray(responseData, length);
  }

  /*服务端反序列化接收的RPC请求*/
  static void AnalyzeRequest(const Request &request,
			     uuid_t &uuid,
			     string &serviceName,
			     string &methodName,
			     Message &parameters)
  {
    memcpy(&uuid, request.uuid().c_str(), sizeof(uuid_t));
    serviceName = request.servicename();
    methodName = request.methodname();
    if (!parameters.ParseFromString(request.parameters()))
      throw RPCError(BAD_PARAMETER_DATA, "Fail to deserialize RPC parameter data");
  }
  void DeserializeRequest(const string &requestData,
			  uuid_t &uuid,
			  string &serviceName,
			  string &methodName,
			  Message &parameters)
  {
    Request request;
    if (!request.ParseFromString(requestData))
      throw RPCError(BAD_REQUEST_DATA, "Fail to desrialize RPC request data");
    AnalyzeRequest(request, uuid, serviceName, methodName, parameters);
  }

  void DeserializeRequest(void *requestData,
			  int length,
			  uuid_t &uuid,
			  string &serviceName,
			  string &methodName,
			  Message &parameters)
  {
    Request request;
    if (!request.ParseFromArray(requestData, length))
      {
	throw RPCError(BAD_REQUEST_DATA, "Fail to desrialize RPC request data");
      }
    AnalyzeRequest(request, uuid, serviceName, methodName, parameters);
  }

  /*客户端反序列化接收的RPC响应*/
  static void AnalyzeResponse(const Response &response,
			      uuid_t &uuid,
			      Message &result)
  {
    if (response.has_error())
      {
	Error error = response.error();
	throw RPCError(error.code(), error.detail());
      }
    
    memcpy(&uuid, response.uuid().c_str(), sizeof(uuid_t));
    if (!result.ParseFromString(response.result()))
      throw RPCError(BAD_RESULT_DATA, "Fail to deserialize RPC result data");
  }
      
  void DeserializeResponse(const string &responseData,
			   uuid_t &uuid,
			   Message &result)
  {
    Response response;
    if (!response.ParseFromString(responseData))
      {
	throw RPCError(BAD_RESPONSE_DATA, "Fail to deserialize RPC response data");
      }
    AnalyzeResponse(response, uuid, result);
  }

  void DeserializeResponse(void *responseData,
			   int length,
			   uuid_t &uuid,
			   Message &result)
  {
    Response response;
    if (!response.ParseFromArray(responseData, length))
      {
	throw RPCError(BAD_RESPONSE_DATA, "Fail to deserialize RPC response data");
      }
    AnalyzeResponse(response, uuid, result);
  }
}
